/**
 * 
 */
package truerefactor.metrics;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

import truerefactor.graph.Accessibility;
import truerefactor.graph.ClassNode;
import truerefactor.graph.CodeGraph;
import truerefactor.graph.CodeNode;
import truerefactor.graph.MethodNode;

/**
 * RFC - An implementation of the Request For Class metric
 * 
 * @author Isaac Griffith
 */
public class RFC extends Metric {

    /**
     * Creates a new instance of the RFC metric
     */
    public RFC()
    {
        this.shortName = "RFC";
        this.name = "Response For A Class";
        this.description = "";
    }

    /*
     * (non-Javadoc)
     * @see truerefactor.metrics.Metric#measure(truerefactor.graph.CodeGraph)
     */
    @Override
    public double measure(CodeGraph graph)
    {
        // RFC is the largest set of methods in a class execution path. The
        // cardinality of that set is the found rfc.

        double cRFC = 0;
        double tRFC = 0;
        double mRFC = 0;

        // RFC = All possible responses for a class at any given time
        // cRFC = class RFC
        // tRFC = total RFC summed across all cRFC's
        // mRFC = mean RFC

        List<ClassNode> classes = graph.getClasses();
        for (ClassNode cNode : classes)
        {
            cRFC = measure(cNode);
            tRFC += cRFC;
        }

        mRFC = tRFC / classes.size();

        return mRFC;
    }

    /**
     * Measures the request for class of the provided classnode
     * 
     * @param cNode
     *            classnode to measure
     * @return the RFC of the given classnode
     */
    public static int measure(ClassNode cNode)
    {
        List<CodeNode> methods = cNode.getMethods();
        Queue<MethodNode> search = new LinkedList<MethodNode>();
        Set<MethodNode> selected = new HashSet<MethodNode>();

        for (CodeNode node : methods)
        {
            if (node instanceof MethodNode)
            {
                MethodNode method = (MethodNode) node;

                if (!method.getAccessibility().equals(Accessibility.Private))
                {
                    search.offer(method);
                }
            }
        }

        while (!search.isEmpty())
        {
            MethodNode current = search.poll();
            selected.add(current);
            search.addAll(current.getAssociatedMethods());

            search.removeAll(selected);
        }

        return selected.size();
    }
}
